54 绘制曲线图
54.1 引言曲线图的力量
曲线图(Line Plot)是最基础也是最重要的数据可视化形式之一。在金融领域,曲线图帮助我们: - 观察趋势:识别价格的上升、下降、震荡趋势 - 发现模式:识别季节性、周期性模式 - 比较表现:对比不同资产的表现 - 监控变化:实时跟踪关键指标的变化
54.2 曲线图的数学基础
曲线图本质上是函数的可视化: \[ y = f(x) \]
在金融时间序列中: - 自变量 \(x\): 时间 \(t\) - 因变量 \(y\): 价格、收益率、成交量等
连续与离散: - 理论上,价格是离散的(仅在交易时刻有定义) - 但为了可视化,我们用线段连接相邻点,形成连续曲线 - 这种线性插值假设价格在交易间隔内平滑变化
54.3 基础曲线图单条线
平台任务1解答代码
以下代码与教学平台任务要求完全一致:
# 注:numpy_financial包本地未安装,但平台已经内置
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import numpy as np # 导入NumPy数值计算库
import pandas as pd # 导入Pandas数据分析库
import matplotlib.pyplot as plt #导入matplotlab的子模块pyplot
import numpy_financial as nmf # 导入NumPy库
plt.rcParams["font.sans-serif"] = ["SimHei"] # 设置Matplotlib全局参数
r = 0.049 #贷款的年利率
n = 30 #贷款的期限(年)
principle = 6e6 #贷款的本金
pay_month = nmf.pmt(rate=r/12,nper=n*12,pv=principle,fv=0,when="end") # 计算等额本息月供金额
print("在等额本息规则下丁先生每月偿还的金额",-round(pay_month,2)) # 输出在等额本息规则下丁先生每月偿还的金额
t = np.arange(n*12)+1 #生成一个包含每次还款期限长度的数组
principle_pay_month = nmf.ppmt(rate=r/12,per=t,nper=n*12,pv=principle,fv=0,when="end") #计算每月偿还的本金额
interest_pay_month = nmf.ipmt(rate=r/12,per=t,nper=n*12,pv=principle,fv=0,when="end") #计算每月偿还的利息额
pay_month_array = pay_month*np.ones_like(principle_pay_month) #创建一个每月偿还的数组
plt.figure(figsize=(9,6)) # 创建图形画布
plt.plot(t,-pay_month_array,"r-",label=u"每月偿还金额",lw=2.5) # 绑制折线图
plt.plot(t,-principle_pay_month,"m--",label=u"每月偿还本金金额",lw=2.5) # 绑制折线图
plt.plot(t,-interest_pay_month,"b--",label =u"每月产股韩利息金额",lw=2.5) # 绑制折线图
plt.xticks(fontsize=14) # 设置X轴刻度标签
plt.xlabel(u"逐次偿还的期限(月)",fontsize=14) # 设置X轴标签
plt.yticks(fontsize=13) # 设置Y轴刻度标签
plt.ylabel(u"金额",fontsize=14) # 设置Y轴标签
plt.title(u"等额本息还款规则下每月偿还的金额以及本金额与利息额") # 设置图表标题
plt.legend(loc=0,fontsize=13) # 添加图例
plt.grid() # 显示网格线
plt.savefig("1.png") # 保存图形至文件平台任务2解答代码
以下代码与教学平台任务要求完全一致:
# 注:numpy_financial包本地未安装,但平台已经内置
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import numpy as np # 导入NumPy数值计算库
import matplotlib.pyplot as plt #导入matplotlab的子模块pyplot
import numpy_financial as nmf # 导入NumPy库
plt.rcParams["font.sans-serif"] = ["SimHei"] # 设置Matplotlib全局参数
r = 0.049 #贷款的年利率
n = 30 #贷款的期限(年)
principle = 6e6 #贷款的本金
r_list = np.linspace(0.02,0.08,100) #生成贷款利率的一个数组
pay_month = nmf.pmt(rate=r/12,nper=n*12,pv=principle,fv=0,when="end") # 计算等额本息月供金额
pay_month_list = nmf.pmt(rate=r_list/12,nper=n*12,pv=principle,fv=0,when="end") #计算不同贷款利率条件下的每月偿还本息之和
plt.figure(figsize=(9,6)) # 创建图形画布
plt.plot(r_list,-pay_month_list,"r-",label=u"每月偿还金额",lw=2.5) # 绑制折线图
plt.plot(r,-pay_month,"bo",label=u"贷款利率4.9%的每月偿还金额") # 绑制折线图
plt.xticks(fontsize=14) # 设置X轴刻度标签
plt.xlabel(u"贷款利率",fontsize=14) # 设置X轴标签
plt.yticks(fontsize=14) # 设置Y轴刻度标签
plt.ylabel(u"金额",fontsize=14,rotation=90) # 设置Y轴标签
plt.legend(loc=0,fontsize=13) # 添加图例
plt.grid() # 显示网格线
plt.savefig("2.png") # 保存图形至文件平台任务3解答代码
以下代码与教学平台任务要求完全一致:
# 注:numpy_financial包本地未安装,但平台已经内置
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import numpy as np # 导入NumPy数值计算库
import matplotlib.pyplot as plt #导入matplotlab的子模块pyplot
import numpy_financial as nmf # 导入NumPy库
plt.rcParams["font.sans-serif"] = ["SimHei"] # 设置Matplotlib全局参数
r = 0.049 #贷款的年利率
n = 30 #贷款的期限(年)
principle = 6e6 #贷款的本金
t = np.arange(n*12)+1 #生成一个包含每次还款期限长度的数组
prin_month = principle/(n*12) #计算等额本金还款规则下的每月本金还款额
prin_month_array = np.ones(n*12)*prin_month #生成一个每月本金还款额的数组
int_month_array = np.zeros_like(prin_month_array) #生成存放每月利息还款额的初始数组
for i in np.arange(n*12): # 遍历np.arange(n*12)中的每个i
int_month_array[i] = (principle-i*prin_month)*r/12 #计算逐月支付的利息额
pay_total_month = prin_month_array+int_month_array #j计算等额本金还款规则下的每月还款总额
plt.figure(figsize=(9,6)) # 创建图形画布
plt.plot(t,pay_total_month,"m-",label=u"每月偿还金额",lw=2.5) # 绑制折线图
plt.plot(t,prin_month_array,"y--",label=u"每月偿还本金额",lw=2.5) # 绑制折线图
plt.plot(t,int_month_array,"c--",label =u"每月偿还利息额",lw=2.5) # 绑制折线图
plt.xticks(fontsize=14) # 设置X轴刻度标签
plt.xlabel(u"逐次偿还的期限(月)",fontsize=14) # 设置X轴标签
plt.yticks(fontsize=14) # 设置Y轴刻度标签
plt.ylabel(u"金额",fontsize=14,rotation=90) # 设置Y轴标签
plt.title(u"等额本金还款规则下每月偿还的金额以及本金额与利息额",fontsize=14) # 设置图表标题
plt.legend(loc=0,fontsize=13) # 添加图例
plt.grid() # 显示网格线
plt.savefig("3.png") # 保存图形至文件# =============================================================================
# 题目:基础曲线图——贵州茅台股价走势
# =============================================================================
# 本任务演示如何使用Matplotlib绘制基础曲线图,展示单条时间序列数据
# 应用场景:可视化单个资产的股价走势
# ==================== 导入必要的库 ====================
import matplotlib.pyplot as plt # Matplotlib的pyplot接口,提供类似MATLAB的绘图API
import pandas as pd # Pandas数据分析库,用于数据处理
import numpy as np # NumPy数值计算库
# ==================== 设置中文字体支持 ====================
# Matplotlib默认不支持中文显示,需要手动设置中文字体
# plt.rcParams是一个全局配置字典,用于控制绘图的各种属性
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置默认字体为黑体(SimHei),确保中文正常显示
plt.rcParams['axes.unicode_minus'] = False # 解决负号'-'显示为方块的问题
# 这两行设置确保图表中的中文文字和负号都能正确显示
# ==================== 创建示例数据 ====================
# 场景:模拟贵州茅台30个交易日的股价数据
# pd.date_range()生成日期序列
# '2024-01-01':起始日期
# periods=30:生成30个日期(30个交易日)
dates = pd.date_range('2024-01-01', periods=30)
# 使用列表推导式生成模拟股价数据
# 基础价格1850元
# i * 2:每天上涨2元(模拟上涨趋势)
# np.random.randn() * 10:添加随机波动,标准差为10元
prices = [1850 + i * 2 + np.random.randn() * 10 for i in range(30)]
# prices是一个包含30个价格的列表,模拟真实股价的随机波动
# 创建DataFrame便于数据管理
# DataFrame是Pandas的核心数据结构,类似Excel表格
df = pd.DataFrame({
'日期': dates, # 日期列,作为X轴
'收盘价': prices # 收盘价列,作为Y轴
})
# ==================== 绘制基础曲线图 ====================
# plt.figure()创建一个新的图形窗口
# figsize=(12, 6):图形大小为12英寸宽×6英寸高
# 这个比例适合展示时间序列数据,宽度较大以容纳更多时间点
plt.figure(figsize=(12, 6))
# plt.plot()绘制折线图(曲线图)
# df['日期']:X轴数据(时间序列)
# df['收盘价']:Y轴数据(价格)
# linewidth=2:线条宽度为2,使折线更清晰可见
# color='#2E86AB':线条颜色,使用十六进制颜色代码(深蓝色)
plt.plot(df['日期'], df['收盘价'], linewidth=2, color='#2E86AB')
# ==================== 设置图表装饰 ====================
# plt.title()设置图表标题
# fontsize=16:标题字号为16(较大,突出显示)
# fontweight='bold':标题文字加粗
plt.title('贵州茅台股价走势', fontsize=16, fontweight='bold')
# plt.xlabel()设置X轴标签
# fontsize=12:标签字号为12
plt.xlabel('日期', fontsize=12)
# plt.ylabel()设置Y轴标签
plt.ylabel('收盘价(元)', fontsize=12)
# plt.grid()添加网格线,帮助读取数值
# True:显示网格线
# alpha=0.3:网格线透明度为0.3(使网格不显眼,不干扰数据)
plt.grid(True, alpha=0.3)
# plt.xticks()设置X轴刻度标签的显示方式
# rotation=45:刻度标签旋转45度(防止日期文字重叠)
plt.xticks(rotation=45)
# plt.tight_layout()自动调整布局,防止元素重叠(如标题被截断)
plt.tight_layout()
# plt.show()将图形显示出来
plt.show()
# ==================== 输出数据统计信息 ====================
print('数据统计:')
# df['收盘价'].describe()计算收盘价的描述性统计量
# 包括:计数、均值、标准差、最小值、四分位数、最大值
print(df['收盘价'].describe())代码解析:
中文字体设置:
plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = FalseSimHei:黑体,确保中文正常显示unicode_minus:解决负号显示问题
plot函数参数:
linewidth:线宽,数值越大线越粗color:颜色,可以用十六进制、RGB、英文名称linestyle:线型,'-'(实线)、'--'(虚线)、':'(点线)
图表装饰:
title:标题xlabel/ylabel:轴标签grid:网格线tight_layout:自动调整布局,避免元素重叠
54.4 多条曲线对比
# =============================================================================
# 题目:多条曲线对比——不同股票价格走势
# =============================================================================
# 本任务演示如何在同一图表中绘制多条曲线,对比不同资产的表现
# ==================== 创建多只股票数据 ====================
# 场景:模拟三只股票30个交易日的价格数据
# 使用之前生成的dates作为时间序列
stocks_data = pd.DataFrame({
'日期': dates,
# 贵州茅台:高价股(1850元起),每天上涨1.5元,标准差8元
'贵州茅台': [1850 + i * 1.5 + np.random.randn() * 8 for i in range(30)],
# 五粮液:中价股(220元起),每天上涨0.8元,标准差5元
'五粮液': [220 + i * 0.8 + np.random.randn() * 5 for i in range(30)],
# 招商银行:低价股(45元起),每天上涨0.3元,标准差2元
'招商银行': [45 + i * 0.3 + np.random.randn() * 2 for i in range(30)]
})
# ==================== 绘制多条曲线 ====================
plt.figure(figsize=(12, 6))
# 绘制第一条曲线:贵州茅台(红色)
# label参数设置图例标签,将在图例中显示
plt.plot(stocks_data['日期'], stocks_data['贵州茅台'],
label='贵州茅台', linewidth=2, color='#E3120B')
# 绘制第二条曲线:五粮液(青色)
plt.plot(stocks_data['日期'], stocks_data['五粮液'],
label='五粮液', linewidth=2, color='#008080')
# 绘制第三条曲线:招商银行(深灰色)
plt.plot(stocks_data['日期'], stocks_data['招商银行'],
label='招商银行', linewidth=2, color='#2C3E50')
# ==================== 设置图表装饰 ====================
plt.title('不同股票价格走势对比', fontsize=16, fontweight='bold')
plt.xlabel('日期', fontsize=12)
plt.ylabel('收盘价(元)', fontsize=12)
# plt.legend()显示图例
# loc='best':自动选择最佳位置(避免遮挡数据)
# fontsize=11:图例字号为11
plt.legend(loc='best', fontsize=11)
plt.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# ==================== 输出各股票统计信息 ====================
print('各股票统计信息:')
# describe()对每只股票分别计算统计量
print(stocks_data.describe())视觉层次设计:
当绘制多条曲线时,需要考虑: 1. 颜色选择:使用对比度高、易于区分的颜色 2. 线宽:主要数据用较粗的线,次要数据用较细的线 3. 图例位置:loc='best'自动选择最佳位置 4. Y轴范围:如果数据量级差异大,考虑用双Y轴或归一化
54.5 双Y轴图
# =============================================================================
# 题目:双Y轴图——价格与成交量
# =============================================================================
# 本任务演示如何创建双Y轴图表,同时展示量价关系
# 应用场景:分析价格与成交量、收益率与波动率等不同量级的数据
# ==================== 创建价格和成交量数据 ====================
df_dual = pd.DataFrame({
'日期': dates,
# 收盘价:45元起,每天上涨0.5元,标准差3元
'收盘价': [45 + i * 0.5 + np.random.randn() * 3 for i in range(30)],
# 成交量:5000手起,每天增加100手,标准差500手
# 成交量与价格的量级不同(价格是几十,成交量是几千),需要双Y轴
'成交量': [5000 + i * 100 + np.random.randn() * 500 for i in range(30)]
})
# ==================== 创建图表和轴对象 ====================
# plt.subplots()创建图形和轴对象
# fig:图形对象,包含整个图形
# ax1:左Y轴对象(第一个轴)
# figsize=(12, 6):图形大小
fig, ax1 = plt.subplots(figsize=(12, 6))
# ==================== 绘制左Y轴(价格) ====================
color1 = '#E3120B' # 红色,用于价格线
# ax1.set_xlabel()设置X轴标签
ax1.set_xlabel('日期', fontsize=12)
# ax1.set_ylabel()设置左Y轴标签
# color=color1:标签颜色与线条颜色一致,便于识别
ax1.set_ylabel('收盘价(元)', color=color1, fontsize=12)
# ax1.plot()在左Y轴上绘制数据
# color=color1:线条颜色
# linewidth=2:线宽
# label='收盘价':图例标签
line1 = ax1.plot(df_dual['日期'], df_dual['收盘价'],
color=color1, linewidth=2, label='收盘价')
# ax1.tick_params()设置刻度标签样式
# axis='y':只设置Y轴刻度
# labelcolor=color1:Y轴刻度标签颜色与线条颜色一致
ax1.tick_params(axis='y', labelcolor=color1)
# ax1.grid()只在左Y轴添加网格线
ax1.grid(True, alpha=0.3)
# ==================== 创建共享X轴的右Y轴 ====================
# ax1.twinx()创建一个共享X轴的新Y轴(右Y轴)
# 这样两个Y轴对应同一个X轴(时间轴)
ax2 = ax1.twinx()
# ==================== 绘制右Y轴(成交量) ====================
color2 = '#008080' # 青色,用于成交量线
# ax2.set_ylabel()设置右Y轴标签
ax2.set_ylabel('成交量(手)', color=color2, fontsize=12)
# ax2.plot()在右Y轴上绘制数据
# linestyle='--':使用虚线,与实线的价格线区分
line2 = ax2.plot(df_dual['日期'], df_dual['成交量'],
color=color2, linewidth=2, linestyle='--', label='成交量')
# ax2.tick_params()设置右Y轴刻度标签样式
ax2.tick_params(axis='y', labelcolor=color2)
# ==================== 合并图例 ====================
# 因为ax1和ax2各有图例,需要合并成一个统一的图例
# lines = line1 + line2:合并两条线
lines = line1 + line2
# [l.get_label() for l in lines]:提取每条线的标签
labels = [l.get_label() for l in lines]
# ax1.legend()在左Y轴上显示合并后的图例
# lines:线条对象列表
# labels:标签列表
ax1.legend(lines, labels, loc='best', fontsize=11)
# ==================== 设置标题并显示 ====================
plt.title('价格与成交量走势', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.show()双Y轴的使用场景:
- 量价关系:价格与成交量
- 收益率与波动率:收益与风险
- 价格与指标:价格与移动平均线、RSI等技术指标
- 不同量级数据:股价(元)与市值(万亿元)
注意事项: - 双Y轴可能误导读者,需谨慎使用 - 明确标注哪个轴对应哪条线 - 考虑用子图(subplots)替代,更清晰
54.6 填充区域图
# =============================================================================
# 题目:填充区域图——价格区间
# =============================================================================
# 本任务演示如何绘制填充区域图,展示预测区间或置信区间
# 应用场景:布林带、价格预测区间、期权盈亏区间
# ==================== 创建带上下限的数据 ====================
df_area = pd.DataFrame({
'日期': dates,
# 价格:100元起,每天上涨1元,标准差3元
'价格': [100 + i + np.random.randn() * 3 for i in range(30)],
# 上限:105元起,每天上涨1元,标准差2元(价格上方5元)
'上限': [105 + i + np.random.randn() * 2 for i in range(30)],
# 下限:95元起,每天上涨1元,标准差2元(价格下方5元)
'下限': [95 + i + np.random.randn() * 2 for i in range(30)]
})
# ==================== 绘制填充区域图 ====================
plt.figure(figsize=(12, 6))
# 绘制实际价格曲线(深灰色)
plt.plot(df_area['日期'], df_area['价格'],
label='实际价格', linewidth=2, color='#2C3E50')
# plt.fill_between()填充两条曲线之间的区域
# df_area['日期']:X轴数据
# df_area['下限']:区域下边界
# df_area['上限']:区域上边界
# alpha=0.3:透明度0.3(使填充区域不遮挡网格线)
# color='#008080':填充颜色(青色)
# label='预测区间':图例标签
plt.fill_between(df_area['日期'], df_area['下限'], df_area['上限'],
alpha=0.3, color='#008080', label='预测区间')
# ==================== 设置图表装饰 ====================
plt.title('价格走势与预测区间', fontsize=16, fontweight='bold')
plt.xlabel('日期', fontsize=12)
plt.ylabel('价格(元)', fontsize=12)
plt.legend(loc='best', fontsize=11)
plt.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# ==================== 计算区间宽度统计 ====================
print('区间宽度统计:')
# 区间宽度 = 上限 - 下限
df_area['区间宽度'] = df_area['上限'] - df_area['下限']
# describe()计算区间宽度的统计量
print(df_area['区间宽度'].describe())金融应用:
- 置信区间:统计模型预测的置信区间
- 布林带:移动平均线 ± 标准差
- 期权策略:期权到期时的盈亏区间
- 风险管理:VaR(在险价值)的区间表示
fill_between参数: - alpha:透明度(0-1),越小越透明 - color:填充颜色 - where:条件填充,只填充满足条件的区域 - interpolate:在边界处插值,使填充更平滑
54.7 堆叠面积图
# =============================================================================
# 题目:堆叠面积图——投资组合构成
# =============================================================================
# 本任务演示如何绘制堆叠面积图,展示各部分随时间的变化及总体趋势
# 应用场景:投资组合资产配置、公司收入构成、市场份额变化
# ==================== 创建投资组合数据 ====================
df_portfolio = pd.DataFrame({
'日期': pd.date_range('2024-01-01', periods=12), # 12个月
# 股票:100万元起,每月增长5万元,标准差3万元
'股票': [100 + i*5 + np.random.randn()*3 for i in range(12)],
# 债券:80万元起,每月增长2万元,标准差2万元
'债券': [80 + i*2 + np.random.randn()*2 for i in range(12)],
# 现金:20万元起,每月增长0.5万元,标准差1万元
'现金': [20 + i*0.5 + np.random.randn()*1 for i in range(12)]
})
# ==================== 绘制堆叠面积图 ====================
plt.figure(figsize=(12, 6))
# plt.stackplot()绘制堆叠面积图
# df_portfolio['日期']:X轴数据(时间)
# 接下来的三个参数是要堆叠的Y值序列
# df_portfolio['股票']:第一层(最底层)
# df_portfolio['债券']:第二层(堆叠在股票之上)
# df_portfolio['现金']:第三层(最顶层)
# alpha=0.8:透明度0.8(使区域不太透明)
# colors:颜色列表,分别对应三个序列
# labels:标签列表,用于图例
plt.stackplot(df_portfolio['日期'],
df_portfolio['股票'],
df_portfolio['债券'],
df_portfolio['现金'],
alpha=0.8,
colors=['#E3120B', '#008080', '#F0A700'],
labels=['股票', '债券', '现金'])
# ==================== 设置图表装饰 ====================
plt.title('投资组合资产配置变化', fontsize=16, fontweight='bold')
plt.xlabel('日期', fontsize=12)
plt.ylabel('资产价值(万元)', fontsize=12)
# loc='upper left':图例位置在左上角
plt.legend(loc='upper left', fontsize=11)
# axis='y':只显示Y轴网格线(水平网格线)
plt.grid(True, alpha=0.3, axis='y')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# ==================== 计算各资产占比 ====================
print('各资产占比:')
# total:每月的资产总值(股票+债券+现金)
# sum(axis=1):按行求和(横向求和)
total = df_portfolio[['股票', '债券', '现金']].sum(axis=1)
# 计算最新月份(最后一行)各资产占比
for asset in ['股票', '债券', '现金']:
# df_portfolio[asset].iloc[-1]:获取该资产的最后一行值(最新值)
# total.iloc[-1]:获取总资产的最后一行值
ratio = df_portfolio[asset].iloc[-1] / total.iloc[-1]
# f'{asset}: {ratio:.1%}':格式化输出,百分比保留1位小数
print(f'{asset}: {ratio:.1%}')堆叠图的数学含义:
\[ y_{\text{total}} = y_1 + y_2 + \cdots + y_n \]
每层的实际值: \[ y_{\text{layer }i} = \sum_{j=1}^i y_j \]
金融应用: - 资产配置:展示股票、债券、现金的配置变化 - 收入构成:主营业务收入、其他业务收入 - 市场份额:不同公司在市场中的份额变化
54.8 对数坐标轴
# =============================================================================
# 题目:对数Y轴——复利增长可视化
# =============================================================================
# 本任务演示如何使用对数坐标轴展示指数增长数据
# 应用场景:复利增长、投资回报、跨越数量级的数据
# ==================== 创建复利增长数据 ====================
# years:年份序列,从2000年到2023年
years = np.arange(2000, 2024)
initial_value = 100 # 初始值:100元
growth_rate = 0.15 # 年化增长率:15%
# values:使用复利公式计算每年的价值
# (1 + growth_rate) ** (years - 2000):复利因子
# 例如:2000年:(1.15)^0 = 1,价值100元
# 2001年:(1.15)^1 = 1.15,价值115元
# 2002年:(1.15)^2 = 1.3225,价值132.25元
values = initial_value * (1 + growth_rate) ** (years - 2000)
# ==================== 创建对比:线性vs对数 ====================
# plt.subplots(1, 2, figsize=(15, 6))创建1行2列的子图布局
# fig:图形对象
# (ax1, ax2):两个轴对象的元组
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
# ==================== 线性坐标(左图) ====================
# ax1.plot()在第一个子图绘制
ax1.plot(years, values, linewidth=2, color='#E3120B')
ax1.set_title('线性坐标', fontsize=14, fontweight='bold')
ax1.set_xlabel('年份', fontsize=12)
ax1.set_ylabel('价值(元)', fontsize=12)
ax1.grid(True, alpha=0.3)
# ==================== 对数坐标(右图) ====================
# ax2.semilogy()绘制Y轴为对数坐标的图表
# semilogy = semi-logarithmic y-axis(Y轴对数化)
# 在对数坐标下,指数增长呈直线
ax2.semilogy(years, values, linewidth=2, color='#008080')
ax2.set_title('对数坐标', fontsize=14, fontweight='bold')
ax2.set_xlabel('年份', fontsize=12)
# Y轴标签注明"对数",提醒读者
ax2.set_ylabel('价值(元,对数)', fontsize=12)
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# ==================== 输出复利增长分析 ====================
print('复利增长分析:')
print(f'初始值: {initial_value}元')
print(f'年化增长率: {growth_rate:.1%}')
print(f'2023年价值: {values[-1]:.2f}元')
# 计算总增长倍数
print(f'总增长倍数: {values[-1]/initial_value:.1f}倍')对数坐标的金融意义:
线性坐标:展示绝对值变化 对数坐标:展示相对变化(百分比)
在金融中: - 复利效应:对数坐标下,恒定增长率呈直线 - 收益率比较:不同起始点的资产可以直接比较斜率 - 长期趋势:更适合展示跨越数量级的数据
数学原理: \[ \ln(y) = \ln(A \cdot e^{rt}) = \ln(A) + rt \]
在半对数图上,指数增长呈直线,斜率即为增长率 \(r\)。
54.9 金融应用移动平均线
# =============================================================================
# 题目:移动平均线——技术分析基础
# =============================================================================
# 本任务演示如何绘制移动平均线,识别金叉和死叉信号
# 应用场景:技术分析、趋势跟踪、交易信号生成
# ==================== 创建价格数据 ====================
# np.random.seed(42)设置随机种子,确保每次运行结果相同
np.random.seed(42)
# df_price:模拟60个交易日的股价数据
df_price = pd.DataFrame({
'日期': pd.date_range('2024-01-01', periods=60),
# 收盘价:100元起
# np.random.normal(0.5, 2, 60)生成60个正态分布随机数(均值0.5,标准差2)
# np.cumsum()计算累积和,模拟价格的随机游走
'收盘价': 100 + np.cumsum(np.random.normal(0.5, 2, 60))
})
# ==================== 计算移动平均线 ====================
# .rolling(window=5).mean():5日移动平均线
# rolling(5):创建一个5日的滚动窗口
# mean():计算窗口内数据的均值
df_price['MA5'] = df_price['收盘价'].rolling(window=5).mean()
# 20日移动平均线(中期趋势线)
df_price['MA20'] = df_price['收盘价'].rolling(window=20).mean()
# 60日移动平均线(长期趋势线)
df_price['MA60'] = df_price['收盘价'].rolling(window=60).mean()
# ==================== 绘制移动平均线 ====================
plt.figure(figsize=(14, 7))
# 绘制收盘价(深灰色,半透明)
plt.plot(df_price['日期'], df_price['收盘价'],
label='收盘价', linewidth=1.5, color='#2C3E50', alpha=0.7)
# 绘制MA5(红色,短期均线)
plt.plot(df_price['日期'], df_price['MA5'],
label='MA5', linewidth=1.5, color='#E3120B')
# 绘制MA20(青色,中期均线)
plt.plot(df_price['日期'], df_price['MA20'],
label='MA20', linewidth=1.5, color='#008080')
# 绘制MA60(黄色,长期均线,线宽加粗)
plt.plot(df_price['日期'], df_price['MA60'],
label='MA60', linewidth=2, color='#F0A700')
# ==================== 标注金叉和死叉 ====================
# 金叉:短期均线上穿长期均线(买入信号)
# (MA5 > MA20):当前MA5大于MA20
# .shift(1):将数据下移一行,获取前一日的值
# (MA5.shift(1) <= MA20.shift(1)):前一日的MA5小于等于MA20
# 两个条件都满足时,表示MA5刚刚上穿MA20
golden_cross = (df_price['MA5'] > df_price['MA20']) & (df_price['MA5'].shift(1) <= df_price['MA20'].shift(1))
# 死叉:短期均线下穿长期均线(卖出信号)
death_cross = (df_price['MA5'] < df_price['MA20']) & (df_price['MA5'].shift(1) >= df_price['MA20'].shift(1))
# plt.scatter()绘制金叉点(红色向上三角)
# df_price['日期'][golden_cross]:金叉发生的日期
# df_price['MA5'][golden_cross]:金叉点的MA5值
# color='red':红色
# s=100:散点大小为100
# marker='^':向上三角符号
# label='金叉':图例标签
# zorder=5:图层顺序为5(确保散点显示在线条上方)
plt.scatter(df_price['日期'][golden_cross], df_price['MA5'][golden_cross],
color='red', s=100, marker='^', label='金叉', zorder=5)
# plt.scatter()绘制死叉点(绿色向下三角)
plt.scatter(df_price['日期'][death_cross], df_price['MA5'][death_cross],
color='green', s=100, marker='v', label='死叉', zorder=5)
# ==================== 设置图表装饰 ====================
plt.title('移动平均线与交叉信号', fontsize=16, fontweight='bold')
plt.xlabel('日期', fontsize=12)
plt.ylabel('价格(元)', fontsize=12)
plt.legend(loc='best', fontsize=11)
plt.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# ==================== 输出移动平均线统计 ====================
print('移动平均线统计:')
print(df_price[['收盘价', 'MA5', 'MA20', 'MA60']].describe())移动平均线的金融理论:
简单移动平均(Simple Moving Average, SMA): \[ \text{SMA}_t = \frac{1}{n}\sum_{i=0}^{n-1} P_{t-i} \]
交易信号: - 金叉(Golden Cross):短期均线上穿长期均线,买入信号 - 死叉(Death Cross):短期均线下穿长期均线,卖出信号
局限性: - 滞后性:基于历史价格,信号滞后 - 震荡市场:在横盘震荡中频繁产生错误信号 - 参数敏感性:不同周期效果差异大